#! /usr/bin/env python
# -*- coding: utf-8 -*-

import pygtk
import gtk
import os

import OrthoGTK
import StereoGTK
from plane import Plane
import fr_scatdir_module
import NikolGTKGraph
from write_scatpairs_module import write_scatpair
from calculate_scatangle_module import calculate_scateringangle
from fr_belts_intensity import calculate_intensity

class NikolGTK:
    def __init__(self, name, density, PID, pairs, belts):
        self.name = name
        self.density = density
        self.PID = PID
        
        self.pairs =  pairs# list of pairs of conj
        self.cur_pair = [] # curently selected pair
        self.cur_max = [] # currently selected max
        self.plot_scats = None # all directions of a scats to plot
        self.stress = None # stress of cur_pair
        self.state = None
        self.belts = [] # list of belts
        self.cur_belt = None
        if belts: self.belts=belts
        # pixmaps for background images
        orth_pixbuf = gtk.gdk.pixbuf_new_from_file('/tmp/%sortho' % PID)
        stereo_pixbuf = gtk.gdk.pixbuf_new_from_file('/tmp/%sstereo' % PID)
        
        self.win = gtk.Window()
        self.win.connect('destroy', gtk.main_quit)
        self.win.set_size_request(1000,600)
        
        # vertical box that contain all the other widget 
        self.vbox = gtk.VBox()
        
        # horizontal box that contain ortho, stereo
        self.hbox = gtk.HBox(False, 0)
        
        self.vbox.pack_start(self.hbox, False, False, 0)
        
        self.graph = NikolGTKGraph.GTKGraph()
        self.vbox.pack_start(self.graph)
        
        self.statusbar = gtk.Statusbar()
        self.vbox.pack_start(self.statusbar,False,False,0) 

        self.ortho = OrthoGTK.OrthoGTK(orth_pixbuf)
        self.hbox.pack_start(self.ortho)

        self.stereo = StereoGTK.StereoGTK(stereo_pixbuf)
        self.hbox.pack_start(self.stereo)
        
        self.ortho.connect("motion_notify_event", self.mouse_over)
        self.ortho.connect("button_press_event", self.button_press)       
        self.ortho.set_events(gtk.gdk.EXPOSURE_MASK 
                              | gtk.gdk.LEAVE_NOTIFY_MASK
                              | gtk.gdk.BUTTON_PRESS_MASK
                              | gtk.gdk.POINTER_MOTION_MASK
                              | gtk.gdk.POINTER_MOTION_HINT_MASK)

        self.stereo.connect("button_press_event", self.button_press)
        self.stereo.connect("motion_notify_event", self.mouse_over)        
        self.stereo.set_events(gtk.gdk.EXPOSURE_MASK 
                              | gtk.gdk.LEAVE_NOTIFY_MASK
                              | gtk.gdk.BUTTON_PRESS_MASK
                              | gtk.gdk.POINTER_MOTION_MASK
                              | gtk.gdk.POINTER_MOTION_HINT_MASK)
        
        self.graph.connect("button_press_event", self.button_press_graph)
        self.graph.set_events(gtk.gdk.EXPOSURE_MASK 
                              | gtk.gdk.LEAVE_NOTIFY_MASK
                              | gtk.gdk.BUTTON_PRESS_MASK
                              | gtk.gdk.POINTER_MOTION_MASK
                              | gtk.gdk.POINTER_MOTION_HINT_MASK)
        
        self.signal_handler_id = self.win.connect("key_press_event", 
                                                         self.key_press_event)
        
        self.win.add(self.vbox)
        self.win.show_all()
        self.queue()
    
    def button_press_graph(self, widget, event):
        # press buton at a grph. 
        # correct direction of a cur_max
        if self.state == 'graph-0':
            direction =  widget.get_direction(event.x)
            self.cur_pair[1] = direction
            self.queue()
            
        if self.state == 'graph-1':
            direction =  widget.get_direction(event.x)
            self.cur_pair[3] = direction
            self.queue()
            
    def button_press(self, widget, event):
        dr, dp = widget.get_widget_coords(event.x, event.y)
        if [dr, dp] == [None, None]:
            return       
        if self.state == 'new0':
            self.cur_max = Plane(dr, abs(dp-90))
            self.ortho.cur_max = self.cur_max
            self.stereo.cur_max = self.cur_max
            self.ortho.queue_draw() 
            self.stereo.queue_draw() 
            self.state = 'new1'
        elif self.state == 'new1':
            plane1 = self.cur_max
            plane2 = Plane(dr, abs(dp-90))
            # calculate the directions
            pplane = plane1.get_perpendicular_between(plane2).normal()
            dir1 = (pplane.dir+90) % 360
            dir2 = (pplane.dir-90) % 360
            self.cur_max = None
            self.ortho.cur_max = self.cur_max
            self.stereo.cur_max = self.cur_max
            pair = [plane1, dir1, plane2, dir2]
            # Add pair to pairs list
            self.pairs.append(pair)
            self.queue()
            self.state = None 
        elif self.state == "belt_new0":
            self.cur_max = Plane(dr, abs(dp-90))
            self.ortho.cur_max = self.cur_max
            self.stereo.cur_max = self.cur_max
            self.ortho.queue_draw() 
            self.stereo.queue_draw() 
            self.state = 'belt_new1'
        elif self.state == "belt_new1":
            plane1 = self.cur_max
            plane2 = Plane(dr, abs(dp-90))
            # calculate the directions
            pplane = plane1.get_perpendicular_between(plane2).normal()
            self.cur_max = None
            self.ortho.cur_max = self.cur_max
            self.stereo.cur_max = self.cur_max
            self.belts.append(pplane)
            self.queue()
            self.state = None 
            # calculate belt intensity
            print calculate_intensity(self.density, pplane) 
        elif self.state == "select":
            # find max near clicked position
            dp = abs(dp-90)
            for i in range(len(self.pairs)):
                pair = self.pairs[i]
                if (abs(dr-pair[0].dir)<5 and abs(dp-pair[0].dip)<5) or \
                   (abs(dr-pair[2].dir)<5 and abs(dp-pair[2].dip)<5):
                    cur_pair = self.pairs.pop(i)
                    self.cur_pair=cur_pair
                    self.queue()
                    self.state = 'cur_pair'
                    break
        elif self.state == "move_max":
            # select max to be moved
            dp = abs(dp-90)
            if abs(dr-self.cur_pair[0].dir)<5 and \
               abs(dp-self.cur_pair[0].dip)<5:
                self.cur_max = self.cur_pair[2] 
                self.cur_pair = None
                self.queue()
                self.state = 'new1'
            elif abs(dr-self.cur_pair[2].dir)<5 and \
                 abs(dp-self.cur_pair[2].dip)<5:
                self.cur_max = self.cur_pair[0] 
                self.cur_pair = None
                self.queue()
                self.state = 'new1'
        elif self.state == "dir_cor":
            # select max to correct direction
            dp = abs(dp-90)
            if abs(dr-self.cur_pair[0].dir)<5 and \
               abs(dp-self.cur_pair[0].dip)<5:
                self.state='dir_cor-0'
                self.cur_max = self.cur_pair[0] 
                self.queue()
            elif abs(dr-self.cur_pair[2].dir)<5 and \
                 abs(dp-self.cur_pair[2].dip)<5:
                self.state='dir_cor-1'
                self.cur_max = self.cur_pair[2] 
                self.queue()
        elif self.state == "dir_cor-0":
            dp = abs(dp-90)
            cplane = Plane(dr, dp)
            pplane = self.cur_pair[0].get_perpendicular_between(cplane).normal()
            self.cur_pair[1] = (pplane.dir-90) % 360
            self.cur_max = None
            self.queue()
            self.state='cur_pair'
        elif self.state == "dir_cor-1":
            dp = abs(dp-90)
            cplane = Plane(dr, dp)
            pplane = self.cur_pair[2].get_perpendicular_between(cplane).normal()
            self.cur_pair[3] = (pplane.dir-90) % 360
            self.cur_max = None
            self.queue()
            self.state='cur_pair'
        elif self.state == "graph" or self.state=="graph-0" or\
                                      self.state=="graph-1":
            # select max to see the graph
            dp = abs(dp-90)
            if (abs(dr-self.cur_pair[0].dir)<5 and \
               abs(dp-self.cur_pair[0].dip)<5):
                self.cur_max = self.cur_pair[0]
                self.queue()
                self.state="graph-0"
                plot_data = fr_scatdir_module.return_plot(self.density, \
                                          self.cur_pair[0])
                self.graph.show(plot_data, self.cur_pair[1])
            if (abs(dr-self.cur_pair[2].dir)<5 and \
               abs(dp-self.cur_pair[2].dip)<5):
                self.cur_max = self.cur_pair[2]
                self.queue()
                self.state="graph-1"
                plot_data = fr_scatdir_module.return_plot(self.density, \
                                        self.cur_pair[2])
                self.graph.show(plot_data, self.cur_pair[3])
        elif self.state == "info":
            # info mode
            dp = abs(dp-90)
            print  self.density.get(Plane(int(dr),int(dp)))   
        elif self.state == "del_all":
            # delete all pairs in wich curent max occured
            dp = abs(dp-90)
            i = 0
            while i < len(self.pairs):
                pair = self.pairs[i]
                if (abs(dr-pair[0].dir)<5 and abs(dp-pair[0].dip)<5) or \
                   (abs(dr-pair[2].dir)<5 and abs(dp-pair[2].dip)<5):
                    self.pairs.pop(i)
                i+=1
            self.state = None
            self.queue()
            


    def queue(self):
        self.stereo.pairs = self.pairs
        self.ortho.pairs = self.pairs
        self.ortho.cur_pair = self.cur_pair
        self.stereo.cur_pair = self.cur_pair
        self.ortho.cur_max = self.cur_max
        self.stereo.cur_max = self.cur_max
        self.ortho.scats = self.plot_scats
        self.stereo.scats = self.plot_scats
        self.stereo.stress = self.stress
        self.stereo.belts = self.belts
        self.ortho.belts = self.belts
        self.stereo.cur_belt = self.cur_belt
        self.ortho.cur_belt = self.cur_belt
        self.ortho.queue_draw() 
        self.stereo.queue_draw() 
        
    def mouse_over(self, widget, event):
        dr, dp = widget.get_widget_coords(event.x, event.y)
        if [dr, dp] == [None, None]:
            return  
        if self.state == "cur_pair":
            aplane, adir = self.cur_pair[0], self.cur_pair[1]
            bplane, bdir = self.cur_pair[2], self.cur_pair[3]
            isDirAppart, isOneHalf, mscatangle, dscatangle = \
                calculate_scateringangle( \
                Plane(aplane.dir,abs(90-aplane.dip)), adir,\
                Plane(bplane.dir, abs(90-bplane.dip)), bdir)
            self.statusbar.push(0,"IsOneHalf: %s, ascat %i, bscat %i " \
                              % (isOneHalf, mscatangle, dscatangle))
            pplane = aplane.get_perpendicular_between(bplane).normal()
            ppA = max((pplane.dir)%360, (pplane.dir+180)%360)
            ppB = ppA - 180
            t = [(adir < ppA and adir > ppB), (bdir < ppA and bdir > ppB)]
            #self.statusbar.push(0,"PPA: %s, PPB: %s, %s" \
            #                  % (ppA, ppB, isDirAppart))
            return
        self.statusbar.push(0,"%i %i" % (dr, dp))
        if widget == self.ortho:
            pass
        elif widget == self.stereo:
            pass
        
    def key_press_event(self, widget, event):
        keyname = gtk.gdk.keyval_name(event.keyval)
        if self.state==None and (keyname=='n' or keyname=='space'):
            self.state = 'new0'
            print 'new max'
        elif self.state==None and keyname=='s':
            self.state = 'select'
            print 'select'
        elif self.state==None and keyname=='S':
            # belt select
            self.state = 'select_belt'
            print 'select belt'
            self.cur_belt=self.belts.pop(0)
            self.queue()
            self.state = 'cur_belt'
        elif self.state=='cur_belt' and keyname=='Tab':
            self.belts.append(self.cur_belt)
            self.cur_belt=self.belts.pop(0)
            self.queue()
        elif keyname=='Escape' or keyname=='q':
            self.state = None
            self.cur_max = None
            self.plot_scats= None
            self.stress = None
            if self.cur_pair:
                self.pairs.append(self.cur_pair)
                self.cur_pair = None
            if self.cur_belt:
                self.belts.append(self.cur_belt)
                self.cur_belt = None
            self.queue()
        elif self.state=='cur_pair' and keyname=='d':
            # delete cu_pair
            self.cur_pair=None
            self.queue()
            self.state=None
        elif keyname=='d' and self.state == 'cur_belt':
            # delete cur belt
            self.state=None
            self.cur_belt=None
            self.queue()

        elif self.state=='cur_pair' and keyname=='r':
            # reverse directions
            self.cur_pair[1] = (self.cur_pair[1]+180) % 360
            self.cur_pair[3] = (self.cur_pair[3]+180) % 360
            self.queue()
        elif self.state=='cur_pair' and keyname=='m':
            # select max to move
            self.state='move_max'
        elif self.state=='cur_pair' and keyname=='c':
            # correct the direction
            self.state='dir_cor'
        if keyname=='l':
            # print list of pairs
            for i, pair in enumerate(self.pairs):
                print '%02i | %003d %02d dir:%003d | %003d %02d dir:%003d' % \
                (i, pair[0].dir, abs(90-pair[0].dip), pair[1], 
                    pair[2].dir, abs(90-pair[2].dip), pair[3])
            if self.cur_pair:
                print '%003d %02d dir:%003d | %003d %02d dir:%003d ' % \
                (self.cur_pair[0].dir, abs(90-self.cur_pair[0].dip), self.cur_pair[1], 
                 self.cur_pair[2].dir, abs(90-self.cur_pair[2].dip), self.cur_pair[3])
        if keyname=='w' and self.state==None:
            # write all pairs to the files
            self.write_to_file()
        if keyname=='W' and self.state==None:
            # write all pairs to the files
            self.write_to_file(rewrite=True)
        if keyname=='g' and self.state=='cur_pair':
            # select max to see the graph
            self.state = 'graph'
        if keyname=='i' and self.state==None:
            # info mode
            self.state='info'
        if (keyname=='p' and self.state=='graph-0') or \
           (keyname=='p' and self.state=='graph-1'):
            #plot self.scats
            print 'plot'
            if self.state=='graph-0':
                plot_data = fr_scatdir_module.return_plot(self.density, \
                                          self.cur_pair[0])
                self.plot_scats=plot_data 
                self.queue()
            if self.state=='graph-1':
                plot_data = fr_scatdir_module.return_plot(self.density, \
                                          self.cur_pair[2])
                self.plot_scats=plot_data 
                self.queue()
        if keyname=='D' and self.state == None:
            self.state = 'del_all'
        if keyname=='S' and self.state == 'cur_pair':
            # draw stress
            os.system("echo %003d %02d %003d > /tmp/fr_nikol_conj.txt" % \
                  (self.cur_pair[0].dir, self.cur_pair[0].dip, self.cur_pair[1]))
            os.system("echo %003d %02d %003d >> /tmp/fr_nikol_conj.txt" % \
                  (self.cur_pair[2].dir, self.cur_pair[2].dip, self.cur_pair[3]))
            os.system("cat /tmp/fr_nikol_conj.txt | python fr_conj.py -c > /tmp/stress_frnikol.txt")
            f = open('/tmp/stress_frnikol.txt', 'r'); lines = f.readlines()
            f.close()
            stress = map(int, lines[1].split())
            self.stress = [Plane(stress[0], stress[1]), \
                           Plane(stress[2], stress[3]), \
                           Plane(stress[4], stress[5])]
            self.queue()
        if keyname=='b'and self.state == None:
            # draw belt
            print 'belt'
            self.state = 'belt_new0'
        if keyname=='B' and self.state == None:
            # print belt
            for i in self.belts:
                print i, calculate_intensity(self.density, i)
            self.state = 'del_belt'
        elif keyname=='w' and self.state=='del_belt':
            # save belts
            self.state = None
            self.write_belt_to_file()
        elif keyname=='W' and self.state=='del_belt':
            # save belts
            self.state = None
            self.write_belt_to_file(rewrite=True)


    def write_to_file(self, rewrite=False):
        # write all pairs to the files
        file_name = "%s.scatpair" % self.name
        # chek if file exist
        if os.path.exists("%s.0" % file_name):
            if not rewrite:
                print "File %s alredy exists." % file_name
                print "To overwrite it use 'W'"
                return 
            os.system("rm %s.*" % file_name)

        for i in range(len(self.pairs)):
            pair = self.pairs[i]
            pair[0] = Plane(pair[0].dir, abs(90-pair[0].dip))
            pair[2] = Plane(pair[2].dir, abs(90-pair[2].dip))
            write_scatpair (pair[0], pair[1], pair[2], pair[3], \
                           "%s.%s" % (file_name, i))
        print "%s files was writen as %s.[0-%s]" % (i+1 , file_name, i)
            
    def write_belt_to_file(self, rewrite=False ):
        # write all belts to the files
        file_name = "%s.belt" % self.name
        # chek if file exist
        if os.path.exists("%s.0" % file_name):
            if not rewrite:
                print "File %s alredy exists." % file_name
                print "To overwrite it use 'W'"
                return 
            os.system("rm %s.*" % file_name)

        for i in range(len(self.belts)):
            belt = self.belts[i]
            f = open("%s.%s" % (file_name, i), 'w')
            f.write("%003d %02d\n" % \
                             (belt.dir, belt.dip))
            f.close
        print "%s files was writen as %s.[0-%s]" % (i+1 , file_name, i)
            

    def main(self):
        gtk.main()
